package org.wikispeedia.speedlimit;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;


import com.thebuzzmedia.sjxp.XMLParser;
import com.thebuzzmedia.sjxp.XMLParserException;
import com.thebuzzmedia.sjxp.rule.DefaultRule;
import com.thebuzzmedia.sjxp.rule.IRule;
import com.thebuzzmedia.sjxp.rule.IRule.Type;

import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.util.Log;


public class SpeedlimitManager {

	static LocationManager lm;
    static String myname, myemail;
	private static SpeedlimitListener myspeedlimitListener;	
    static int mymph, mykph;
    static int pegMph, pegKph;
    static Float myCog;
    static Float pegCog;
    static double myLatitude;
    static double pegLatitude;
   	static double myLongitude;
   	static double pegLongitude;
   	static double  myAltitude_meters;
   	static double pegAltitude_meters;
   	static String rval1;
   	static Boolean locFound=false;
    static double theSpeedLimitIs_latitude=0.0;
    static double theSpeedLimitIs_longitude=0.0;
    static double theSpeedLimitIs_cog=0.0;
    static int theSpeedLimitIs_i= -1;
    static double theSpeedLimitIsDouble=0;
    static Integer theSpeedLimitIs_Integer=0;
    static String  theCopyrightIs;
    static double min_distance=2000.0;
    static double Global_min_distanceFt=2000.0;
	private int positionChanged;
	private int timeChanged;	
	private static Timer mmTimer_submit;  
	private static Timer mmTimer_instantSL;
    final Handler mHandler_time = new Handler();
    final static Handler mHandler_distance = new Handler();
    final static Handler mHandler_submit = new Handler();
	private static double mySpeed;
    static Boolean mph_kph=true;	//not sure how to toggle this yet...
    static Boolean test=false;

    private CountDownTimer mCountDownTimer;
    static String pegName="";
	static String pegEmail="";
	static String pegBitcoin="";

	public static Integer imph;
	public static Integer ikph;
	static CharSequence stuff;
	
    
	public SpeedlimitManager(Context baseContext) {

		   lm= (LocationManager) baseContext.getSystemService(Context.LOCATION_SERVICE);
					   
	  	   getMyLocation_oneTimeSetup(lm);
	}

	public void requestChanges(SpeedlimitListener speedlimitListener) {
			
		//save for later
		myspeedlimitListener= speedlimitListener;	
		
	}	

    public void deleteNearestSpeedLimitSign() {
    	deletePoint();
    }
    
    public String getVal1() {
    	return theString;
    }
    
    static Boolean lockout=false;
    
	public void submit(String name, String email, int mph, int kph, String bitcoin) {

		lockout=true;
		
		//store new mph
		pegMph= mph;	
		pegKph= kph;
		pegName=name;
		pegEmail=email;
		pegBitcoin= bitcoin;
 		if(mph>0 && kph==0) {
 			mph_kph= true;
 		} else {
 			mph_kph= false;		//if mph and kph are both 0 thats an error. Not coded...
 		}

 		
		
			getMyLocation();
			pegLatitude= myLatitude;
			pegLongitude=myLongitude;
			pegAltitude_meters= myAltitude_meters;
			pegCog= myCog;			
 			   	 		
		        
 					startLongRunningOperation_submit();
 					Log.d("TAGGGG","done, After  submitting to submitToWikiSPEEDia!");
 					
 					mCountDownTimer=null;
 				
	 		
	 		
	 		
	 		
		
		

 		
      	//Log.d("TAGG","Try to prevent old/new fighting: clearSigns()");
      	//clearSigns();
      	//theString=  "4";

			
		  
		
	}
	

	private void getMyLocation_oneTimeSetup(LocationManager lm) {
        //float meters;
        
	 	LocationListener locationListener_distance, locationListener_time;

        locationListener_distance = new LocationListener() {
            public void onLocationChanged(Location newloc) {
               positionChanged++;
               Log.d("TAGG","positionChanged= " + Integer.toString(positionChanged));
      		   startLongRunningOperation_distance();
            }
            public void onProviderDisabled(String provider) {} 
            public void onProviderEnabled(String provider) {}
            public void onStatusChanged(String provider, int status,
            		Bundle extras) {}
        };  
        
        float meters= (float)800.0;	// .002 lat,lng is 1 miles square. which is 1609meters.
	 	//fancy way of creating one constant from other...   	 
        //double d=haversign(       35.0,        35.0,       -89.0, -89.0 + .02 );

	 	//if(mph_kph){
	 	//	meters= (float) (d * 5280/3);   //miles to meters (roughly)
	 	//} else {
	 	//	meters= (float) (d * 1000);	  //km to m		   
	 	//}	 	   
	 	
        lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, meters, locationListener_distance);

        
        locationListener_time = new LocationListener() {
            public void onLocationChanged(Location newloc) {
            	timeChanged++;
                //Log.d("TAGG","timeChanged= " + Integer.toString(timeChanged));      
                 	
            	startLongRunningOperation_time();
            }
            public void onProviderDisabled(String provider) {} 
            public void onProviderEnabled(String provider) {}
            public void onStatusChanged(String provider, int status,
            		Bundle extras) {}
        };          
        long ms= 5000; //every 5seconds. So if you are at a red light, speed heads to zero
        //this doesnt work. It always hits at 1 second no matter what value I give for ms
        lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, ms, 0, locationListener_time);        
    }


    private void updateResultsInUi_time() {
    }

    private static void updateResultsInUi_distance() {
    }

    private static void updateResultsInUi_submit() {
    }
    
    // Create runnable for posting
    final Runnable mUpdateResults_time = new Runnable() {
        public void run() {
            updateResultsInUi_time();
        }
    };

    final static Runnable mUpdateResults_distance = new Runnable() {
        public void run() {
            updateResultsInUi_distance();
        }
    };

    final static Runnable mUpdateResults_submit = new Runnable() {
        public void run() {
            updateResultsInUi_submit();
        }
    };
	private static double Global_min_distance = 0;
	

    
    
    
    void startLongRunningOperation_time() {

    	
    	
        // Fire off a thread to do some work that we shouldn't do directly in the UI thread
        Thread t = new Thread("startLongRunningOperation_time") {
            public void run() {
                doSomethingExpensive_time();
                mHandler_time.post(mUpdateResults_time);
            }

			private void doSomethingExpensive_time() {

				getMyLocation();
				
				doSearchThruSigns(
                  		myLatitude, myLongitude, 
                  		myCog, rval1);      
				
				Log.d("TAGG","instant turned off...");
				//instant();
            	
			}
        };
        t.start();
    }
    
    static int ngrabs;
    

    public static void startLongRunningOperation_distance() {

        // Fire off a thread to do some work that we shouldn't do directly in the UI thread
        Thread t = new Thread("startLongRunningOperation_distance") {
            public void run() {
                doSomethingExpensive_distance();
                mHandler_distance.post(mUpdateResults_distance);
            }

			private void doSomethingExpensive_distance() {
			      doTranslate(rval1); 
			}
	    };
	    t.start();
    }

        		    
	
    
    private static int instant_counter=0;
	
	   public static void instant() {   	   
		
		//this calls Google and wikispeedia.org is charged money, so avoid calling this instant() routine!!!
		if(theSpeedLimitIs_Integer>0) {
			return;
		}
		
		Log.d("TAGX","in instant= " + Integer.toString(instant_counter));
		
		//call at 1/2 minute, 2 minute, 5 minute only  (1sec each)
		instant_counter++;
		
		if( (instant_counter==(30)) || (instant_counter==(60*2)) || (instant_counter==(60*5))) {		
			Log.d("TAGX","not 30 120 300");
		} else {
			return;
		}		
		
		theString= "reverse-geocode";
		Log.d("TAGX",theString);
		
		
		StringBuffer response = new StringBuffer("");
		/*
		 *    START SIGN QUERY
		 * 
		 */
		URL url = null;
		
		String latlngString= Double.toString(myLatitude) + "," + Double.toString(myLongitude);
			
       try {        		
       	url = new URL("http://www.wikispeedia.org/speedlimit/geo.php" +		
       			"?latlng=" + latlngString);			 
       	//System.out.println(url.toString());
       } catch (MalformedURLException e) {
       	//Log.e(e.getMessage(), null);
       }

       if (url != null) {
       	try {
       		HttpURLConnection urlConn = (HttpURLConnection) url
               	.openConnection();
       		
       		//TODO I GET ANR KEY TIMEOUTS FROM THIS NEXT LINE. NOT SURE HOW TO FIX!!!!
               BufferedReader in = new BufferedReader(new InputStreamReader(
               		urlConn.getInputStream()));
               String inputLine;
               int amount=0;
               while (   ((amount++)<500) &&       ((inputLine = in.readLine()) != null)         ) {	
               	//System.out.println(inputLine);
               	response.append( inputLine );
               }       
               //Log.d("TAGG","amount= " + Integer.toString(amount));
               in.close();
               urlConn.disconnect();

       	} catch (IOException e) {
       		System.out.println(e.toString());
       	}
       }
       /*
        *     END SIGN QUERY 
        * 
        */
       
		int nlen= response.length();
		if(nlen>0) {			
			int n,m,max;
			n= response.indexOf("mph");
			m= response.indexOf("kph");
			
			max= m>n ? m : n;
			
			if ( max > 0) {
								
				stuff= response.subSequence(0, max-1);
								
				
				
				String str= stuff.toString();
				
				try {
					theSpeedLimitIs_Integer= Integer.parseInt(str.trim());
				} catch ( NumberFormatException e ) {
				}
				
				
				
		       
				
				
				myspeedlimitListener.onSpeedLimitChanged(theSpeedLimitIs_Integer, theCopyrightIs);
	        	//theString= "reverse-geo SL = " + Integer.toString(theSpeedLimitIs_Integer);	   

	        	//TODO add copyright to theString. Dont violate copyright jim
	        	  
	        	  
			}

		}				      
				      
  }//private


		  
		  public static InputStream fromStringBuffer(StringBuffer buf) {
			  return new ByteArrayInputStream(buf.toString().getBytes());
			}

		  

		
	   public static void doTranslate(
		   		String rval1) {   	   

			  //myLatitude= 35.198676;
			  //myLongitude= -89.56558;
		   	  //Log.d("TAGG","Jim REMOVE THIS!!!!!!!!!!!!");

			  
			  
			  
		   
		//   if(myLatitude<0.1 && myLatitude>-0.1) {
		//	   Log.d("TAGG","Emulator is making lat=0 for some reason, just returning from doTranslate");
		//	   return;
		//	   
		 //  }
		   //myLatitude=0.0;
		   //myLongitude=0.0;
		   //Log.d("TAGG","JIM REMOVE!!!!!!!!!!!!");
			   
			   
		   
		StringBuffer response = new StringBuffer("");
		/*
		 *    START SIGN QUERY
		 * 
		 */
		URL url = null;
		
		//By my rough calculation, the most you can travel in 10 seconds (130kph) is 
		//      0.023  (very rough guess). So lets quadruple that and say 0.1 so we don't get too much data!
       try {        		
       	url = new URL("http://www.wikispeedia.org/a/marks_bb2.php" +
       			"?name=all" +
       			"&nelat=" + ( myLatitude + .002) +			//was 0.02
       			"&swlat=" + ( myLatitude - .002) +			//was 0.02
       			"&nelng=" + ( myLongitude + .002) +			//was 0.02
       			"&swlng=" + ( myLongitude - .002));			//was 0.02
       	System.out.println(url.toString());
       } catch (MalformedURLException e) {
       	//Log.e(e.getMessage(), null);
       }

       int amount=0;
       
       if (url != null) {
       	try {
       		HttpURLConnection urlConn = (HttpURLConnection) url
               	.openConnection();
       		
       		//TODO I GET ANR KEY TIMEOUTS FROM THIS NEXT LINE. NOT SURE HOW TO FIX!!!!
               BufferedReader in = new BufferedReader(new InputStreamReader(
               		urlConn.getInputStream()));
               String inputLine;
               //was 500
               while (   ((amount++)<1000) &&       ((inputLine = in.readLine()) != null)         ) {	
               	//System.out.println(inputLine);
               	response.append( inputLine );
               }       
               //Log.d("TAGG","amount= " + Integer.toString(amount));
               in.close();
               urlConn.disconnect();

       	} catch (IOException e) {
       		System.out.println(e.toString());
       	}
       }
       
       if(amount>5) {
    	   	theString= "network down";
    		return;
       }
       

       	Log.d("TAGGG","Amount= " + Integer.toString(amount));
   		Log.d("TAGGG","Asigns.size= " + Integer.toString(signs.size()));

       
       if(true) {

    	 

	       InputStream a= fromStringBuffer(response);
	
	       
	       //testing: Causes XML exception test
	       //String b= "<markers><marker label=\"ALjQdd  <a href=\"http://cieawkmvozgj.com/\">ci\" lat=\"0.00000000\" lng=\"0.00000000\"   mph=\"15\"  kph=\"0\"   cog=\"180\"   alt_meters=\"0.00\" /></markers>";
	   		// convert String into InputStream
	       //a = new ByteArrayInputStream(b.getBytes());
	    
	   	
	   	
	   	
	       try {
	    	   parser.parse(a);
	    	   pass=pass+1;
	       } catch (IllegalArgumentException nsme) {
	    	   fail=fail+1;
	    	   Log.d("TAGG","Err Parser.parse XML Exception pass=" + pass.toString() + " fail=" + fail.toString());		//TODO  Riyad says I need to cleanup a,response...
	    	   return;
	       } catch (XMLParserException nsme) {
	    	   fail=fail+1;
	    	   Log.d("TAGG","Err Parser.parse XML Exception pass=" + pass.toString() + " fail=" + fail.toString());		//TODO  Riyad says I need to cleanup a,response...
	    	   return;
	       } catch (ArrayIndexOutOfBoundsException nsme) {
	    	   fail=fail+1;
	    	   Log.d("TAGG","Err Parser.parse XML Exception pass=" + pass.toString() + " fail=" + fail.toString());		//TODO  Riyad says I need to cleanup a,response...
	    	   return;
	       } catch (Exception e) {
	    	   fail= fail + 1;
	    	   Log.d("TAGG","Err Parser.parse XML Exception pass=" + pass.toString() + " fail=" + fail.toString());		//TODO  Riyad says I need to cleanup a,response...
	    	   return;
	       } 	 
       }
		
  }//private

	   
	   
	   
	   static Integer fail=0;
	   static Integer pass=0;
	   


	   static Signs mySign;
		static String label="";
		static String lat="";

		static String lng="";

		static String mph="";

		static String kph="";

		static String cog="";
		
		/** Queue of Speed Limit Signs */
		static ArrayList<Signs> signs = new ArrayList<Signs>();
		
		static Boolean a0=false;
		static Boolean a1=false;
		static Boolean a2=false;
		static Boolean a3=false;
		static Boolean a4=false;
		static Boolean a5=false;
		static Boolean a6=false;

		
		static IRule markerRule = new DefaultRule(Type.ATTRIBUTE, "/markers/marker",
				"label", "lat", "lng", "mph", "kph", "cog", "alt_meters" ) {
			@Override
			public void handleParsedAttribute(XMLParser parser, int index,
					String value, Object userObject) {
				switch (index) {
				case 0:
					mySign = new Signs();					//this must be first
					//System.out.println("Label: " + value);
					label= value;
				    mySign.label= label;  

					a0=false;
					a1=false;
					a2=false;
					a3=false;
					a4=false;
					a5=false;
					a6=false;
					
					a0=true;
					break;
				case 1:
					//System.out.println("Latitude: " + value);					
					lat=value;
					double latDouble        = Double.valueOf(lat.trim()).doubleValue();
					mySign.lat= latDouble;
					a1=true;
					break;
				case 2:
					//System.out.println("Longitude: " + value);
					lng=value;
					double lonDouble        = Double.valueOf(lng.trim()).doubleValue();
					mySign.lng= lonDouble;
					a2=true;
					break;
				case 3:
					//System.out.println("MPH: " + value);
					mph=value;
					int    mphInt           = Integer.parseInt(mph);
					mySign.mph= mphInt;
					a3=true;
					break;
				case 4:
					//System.out.println("KPH: " + value);
					kph=value;
				    int    kphInt           = Integer.parseInt(kph);
				    mySign.kph= kphInt;
				    a4=true;
					break;
				case 5:
					//System.out.println("COG: " + value);
					cog=value;
					int    cogInt           = Integer.parseInt(cog);
					mySign.cog= Integer.parseInt(cog.trim());
					mySign.cog= cogInt;
					a5=true;
					break;					
				case 6:
					//System.out.println("Altitude: " + value);
										

					if(a0==true && a1==true && a2==true && a3==true && a4==true && a5==true ) {
				       //if it gets here, it parsed good, so save the sign...
						try {  	  
							signs.add(mySign);
							Integer n=signs.size();
							//Log.d("TAGG","In signs.add  signs.size=" + n.toString() );
						} catch (IllegalArgumentException nsme) {
						  	/* failure */
						  	Log.d("TAGG","ERR: cant add to signs List, clearing it. That may help. Not sure if this is best...");
						  	clearSigns();		
						  	theString=  "5";
						}
						Log.d("TAGG","signs.size= " + Integer.toString(signs.size()));
					} else {
						Log.d("TAGG","ERROR: not all tags showed up in xml");						
					}

			    	
			    	
					break;
				}
			}
		};


		@SuppressWarnings("unchecked")
		private static XMLParser parser = new XMLParser(markerRule);

		
		
		

    public static void getMyLocation() {

 	   if(lm != null){
 		   Location loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
 		   if (loc != null) {
 	       		
				if(mph_kph) {
 	       		   mySpeed= loc.getSpeed() * 2.23693629;
 			   } else {
 				   mySpeed= loc.getSpeed() * 3.6;	//1 meter per second = 3.6 kilometers per hour
 			   }
 			   			   

 			   myLatitude= loc.getLatitude();
 	       	   myLongitude= loc.getLongitude();	       	   
 	       	   myAltitude_meters= loc.getAltitude();	       	   
 	       	   myCog= loc.getBearing();	       	   

 	       	   locFound= true;
 	       	   
 			   if(test) {
 				   Log.d("TAGG","TEST!!!!!!!!!!!!!");
 			       mySpeed= 100;
 			       myAltitude_meters= 8527.12;
 			   }

 			   
 			   
 		   } else {
 		   		locFound= false;  //if false, dont trust the mySpeed, etc from above... Used as a lockout since I am a terrible hack!
 		   }
 		   
 	   }
 		   
    }	


			
public static void deletePoint() {

	   
	deletePointAt(theSpeedLimitIs_latitude, theSpeedLimitIs_longitude);    
	
    if(theSpeedLimitIs_i>=0) {    	
    	signs.remove(theSpeedLimitIs_i);
    	theSpeedLimitIs_i= -9;
    }

    
    
	//now delete 3 more around it.
    
    for( int j = 0; j < 3; j++ )	{
		int cog;	
		double distance;
		double min_distance=2000.0;
		double min_latDouble = 0;
		
		double min_lonDouble=0;
		double min_cogDouble = 0;
	
		double lonDouble;
		double latDouble;
		double cogDouble;
	
		int min_i = 0;
		
		int size= signs.size();
		
		if(size==0) {
			return;
		}
	
		//Log.d("TAGG","signs.size= " + Integer.toString(signs.size()));
		
	    for( int i = 0; i < size; i++ )	{
			  Signs mySign= signs.get(i);
		      latDouble= mySign.lat;
		      lonDouble = mySign.lng;
		      cog= mySign.cog;
	    	  distance = computeLatLongDistance( latDouble, lonDouble, theSpeedLimitIs_latitude , theSpeedLimitIs_longitude);
	    	  cogDouble= (double)cog;
	          if(distance < min_distance) {
	        	  min_distance= distance;
	        	  min_latDouble= latDouble;
	        	  min_lonDouble= lonDouble;
	        	  min_cogDouble= cogDouble;
	        	  min_i=i;
	          }
		  }
	    
	      min_distanceFt= (int)(min_distance * 364320);	 //69*5280= 364,320
	    
		  if((min_distanceFt<1000.0) & (cogDiff(theSpeedLimitIs_cog, min_cogDouble) < (double)45.0)) {
			  //declare a winner     	
	    	  deletePointAt(min_latDouble, min_lonDouble);
	
	    	  Log.d("TAGGGGG","Before "+Integer.toString(signs.size()));
	    	  signs.remove(min_i);
	    	  Log.d("TAGGGGG","                After  "+Integer.toString(signs.size()));
	    	  
		  }
    }	
	
	
}
	

public static double computeLatLongDistance( double startLat, double startLong, double endLat, double endLong )
{
    double returnDouble = 0;
   

	double dLat= endLat-startLat;
	double dLon= endLong-startLong;
	
	if(dLat<0.0) dLat= 0.0 - dLat;
	if(dLon<0.0) dLon= 0.0 - dLon;
	
	double d= (dLat) + (dLon);
	
	//this should be scaled and square-rooted, but WHY, just a waste of battery ;-)
	
	returnDouble= d;
	
    //System.out.println("Returning distance: " + returnDouble + " meters");
    return returnDouble;
}



	   public static void deletePointAt(double pointLat, double pointLon) {
    	  
  	   
		   //ck for garbage, cases to ignore...
		   if(pointLat>=0.0 && pointLat<0.000001) {
			   theString= "pointLat=0  delete-IGNORED";
			   return;
		   }
  	   
  	   
		   StringBuffer response = new StringBuffer("");

			/*
			 *    START SIGN QUERY
			 * 
			 */
			URL url = null;

			//crude way to identify point, but I hate to resort to using the "index"....
	        try {
	        	url = new URL("http://www.wikispeedia.org/a/delete_bb2.php" +
	        			"?name=all" +
	        			"&nelat=" + ( pointLat + .00001) +			
	        			"&swlat=" + ( pointLat - .00001) +			
	        			"&nelng=" + ( pointLon + .00001) +			
	        			"&swlng=" + ( pointLon - .00001));		
	        	//System.out.println(url.toString());
	        } catch (MalformedURLException e) {
	        	//Log.e(e.getMessage(), null);
	        }

	        if (url != null) {
	        	try {
	        		HttpURLConnection urlConn = (HttpURLConnection) url
	                	.openConnection();
	                BufferedReader in = new BufferedReader(new InputStreamReader(
	                		urlConn.getInputStream()));
	                String inputLine;
	                while ((inputLine = in.readLine()) != null) {	
	                	//System.out.println(inputLine);
	                	response.append( inputLine );
	                }       
	                in.close();
	                urlConn.disconnect();
	        	} catch (IOException e) {
	        		System.out.println(e.toString());
	        	}
	        }
	        
	        /*
	         *     END SIGN QUERY 
	         * 
	         */			
	        


			zeroOutEverything();
  	  	
	   }

	   
	   public static void zeroOutEverything() {
			//fake out everything in sight to ignore the DELETED sign...
			Global_min_distanceFt= 1000.0;		//was 2000.0;
		   
	   }

	   public static void clearSigns(int tagval) {

		   int n= signs.size();
		   
		   
		   signs.clear();
		   theString= "7";
		   
	   } 
		  
	   
	   public static void clearSigns() {

		   int n= signs.size();
		   int nn;
		   
		   signs.clear();
		   
			   
		  
		   //Log.d("TAGG","All " + Integer.toString(n) + " signs deleted. ");

		   nn= signs.size();
		   
		   //Log.d("TAGG", Integer.toString(nn) + " signs remaining after clearing them all....");
	   }
	   

	   static int min_distanceFt=0;
	   
	   public static int min_distanceFt() {
		   //gives distance to closest

		   return min_distanceFt;
	   }
	   

	   static double old_min_latDouble= 99;
	   static String theString="";
	   
	   
	   public static void doSearchThruSigns(
			   		double myLatitude, double myLongitude, double myCog, String rval1) {   
		   
			int mph=0, kph=0, cog=0;	
			double distance=0.0;
			double min_distance=1000.0;	//was 2000.0;
			double min_latDouble= 0.0;
			int    min_i = 0;
			double min_lonDouble= 0.0;
			double min_cogDouble= 0.0;
			double min_theSpeedLimitIsDouble=0;
			String min_copyright = null;
			double lonDouble=0.0;
			double latDouble=0.0;
			double cogDouble=0.0;
			String copyright;
			        	
			int size= signs.size();
			
			if(size==0) {
				return;
			}

			//Log.d("TAGG","signs.size= " + Integer.toString(signs.size()));
			
		    for( int i = 0; i < size; i++ )	{
		    	
		    	try {  	  
					
					  Signs mySign= signs.get(i);
				      latDouble= mySign.lat;
				      lonDouble = mySign.lng;
				      mph= mySign.mph;
				      kph= mySign.kph;
				      cog= mySign.cog;
					  copyright= mySign.label;
				      double speedlimitDouble= 0.0;
				      if(mph_kph == true) {
					      speedlimitDouble = (double)mph;
				      } else {
			    		  speedlimitDouble = (double)kph;
				      }
				      if(speedlimitDouble<1.0) continue;
		        	  distance = computeLatLongDistance(latDouble, lonDouble, myLatitude , myLongitude);
		        	  cogDouble= (double)cog;
			          //was if(distance < min_distance) {
			          if((distance < min_distance)   &&  (cogDiff(myCog, cogDouble) < (double)45.0)) {		          
			        	  min_theSpeedLimitIsDouble= speedlimitDouble;
			        	  min_distance= distance;
			        	  min_latDouble= latDouble;
			        	  min_lonDouble= lonDouble;
			        	  min_copyright= copyright;
			        	  min_cogDouble= cogDouble;
			        	  min_i= i;
			          }
			          
				} catch (IllegalArgumentException nsme) {
					/* failure */
					Log.d("TAGG","ERR: cant get signs , clearing it. That may help. Not sure if this is best...");
					clearSigns();		
					
				}
		    	
		    	
			  }//for size()
    
		    
		    
		      min_distanceFt= (int)(min_distance * 364320);	 //69*5280= 364,320
		      
		      //if( Math.abs(old_min_latDouble - min_latDouble) > 0.001 ) {
		    	//  theString=   
	    		//	  Integer.toString((int)(min_latDouble*1000.0)) 	+ "L " + 
	    		//	  Integer.toString((int)min_theSpeedLimitIsDouble)  + "S " + 
	    		//	  Integer.toString((int)min_cogDouble)          	+ "C " + 
	    	  	//	  Integer.toString(min_distanceFt)                  + "Ft "+
	    	  	//	  Integer.toString(size)                            + "ns "+
		    	 // 	  Integer.toString(ngrabs)                          + "ng ";
		    	 // 
		    	  //Log.d("TAGGGGG",  theString);
		      //}
 	          old_min_latDouble= min_latDouble;
		    
		    
		    //At 60 MPH you would travel 88 feet per second. 5 x 88 = 440 feet in five seconds.
 	          
		    
			  //watch out. This is my magic constant... Should be DEFed but I am lazy...
			  //was if((min_distanceFt<880.0) & (cogDiff(myCog, min_cogDouble) < (double)45.0)) {
			  if(min_distance<1000.0) {	
					  if(min_distance<= Global_min_distance) {
						  Global_min_distance= min_distance;
			        	  //int d= (int)((min_distance*69*5280)/100)*100;
			              //Log.d("TAGG","Global.rval1= " + rval1);
					  } else {
						  //declare a winner
						  Global_min_distance= 1000.0;
		    	    	  theSpeedLimitIs_Integer=  (int) min_theSpeedLimitIsDouble;
		        		  theCopyrightIs= min_copyright; 
		        		  theSpeedLimitIs_latitude= min_latDouble;
		    	    	  theSpeedLimitIs_longitude= min_lonDouble;
		        		  theSpeedLimitIs_cog= min_cogDouble;
						  theSpeedLimitIs_i= min_i; 
						  //Log.d("TAGG","Declared a winner. SL= " + Integer.toString((int)theSpeedLimitIsDouble) + " " + 
						  //	  Double.toString(theSpeedLimitIs_latitude) + " " + 
						  //      Double.toString(theSpeedLimitIs_longitude));		     	
			        	  if(lockout) {
			        		  //theString="Lockout: not changing speed limit right now";
	    		    	  } else {
	        				  myspeedlimitListener.onSpeedLimitChanged(theSpeedLimitIs_Integer, theCopyrightIs);
		        			  //theString= "Library: dip SL = " + Integer.toString(theSpeedLimitIs_Integer);	   
	        	  		  }
      			  		  Log.d("TAGGGGG",theString);
      			  	  }
			  }
	   }
	 		  	 		  	 	  

	   //computes angle difference using two course-over-ground's in degrees and also returning degree difference 0...360-1
	   public static double cogDiff(double cog1, double cog2) {

		   //code borrowed from my half/angle stuff, 
		   //   so compute half-angles here
		   double cogByTwo_x= cog1 / 2.0;
		   double cogByTwo  = cog2 / 2.0;
		   double i16;
		   double diff;
		   
			//simple algorithm to compute angle error.
		   
		   if(cogByTwo_x >= cogByTwo) {
			   i16= (cogByTwo_x - cogByTwo);
		   } else {
			   i16= (cogByTwo   - cogByTwo_x);
	   	   }
	   	
			if(i16 > 90.0) {
				if(i16 >= 180.0) {
					i16= i16 - 180.0;
				} else {
					i16= 180.0 - i16;
				}
			}

			//convert half-difference into full-difference [0-359]
			diff= i16 * 2.0;

			//Log.d("TAG", "angle: cog1 cog1 diff= " + Double.toString(cog1) + " " + Double.toString(cog2) + " " + Double.toString(diff) );
			
			return diff;	//difference in degrees
	   }
	     
	

	    public static  Object doSomethingExpensive_submitAndOrDelete() throws UnsupportedEncodingException {
	 	   	
	 	   	//Log.d("TAGG","submitAndOrDelete"); 	
 	       
 	        //getMyLocation();
 	       

 	        //trick to sense if they are really trying to delete point instead of submitting one...
 	        if(pegMph>0 || pegKph>0) { 		    	  
 		      
		      	//first delete any close point. 
		      	//If you are setting a point, chances are the last winner is the one you want deleted.
		      	//Only delete it if its close to where you are right now, otherwise leave it alone.
				    double miles= haversign(pegLatitude,  theSpeedLimitIs_latitude,
				    						pegLongitude, theSpeedLimitIs_longitude);			                   	
				    //Log.d("TAGG","miles= " + Double.toString(miles));
		      	if(miles < 0.25) {
		 	        deletePoint(); //this is inside this thread, so its alright here.
		      	} else {
		      		//Log.d("TAGG","no old winner, so we dont delete anthing ");
		      	}
		      	//submit sign to wikispeedia
		      	doSomethingExpensive_submit();
	   
		      	//Log.d("TAGG","clearSigns()");
	 	        //clearSigns();
	 	        //theString=  "2";
	 	       
		      	//Log.d("TAGG","Force query so user doesn't get mad and resubmit existing signs.");
	 	        startLongRunningOperation_distance();  //misnamed: actually gets signs[]
 	        
 	        } else {
 		
	 			Log.d("TAGG","We reduced speed to zero!!, so DELETE last sign...");
		        deletePoint(); //this is inside this thread, so its alright here.
	
		        //Log.d("TAGG","clearSigns()");
	 	        //clearSigns();
	 	        //theString=  "3";

		      	//Log.d("TAGG","Force query so user doesn't get mad and resubmit existing signs.");
	 	        startLongRunningOperation_distance();  //misnamed: actually gets signs[]

 	        }
	      	    
 	        lockout=false;
 	        
			return null;
 		      
	 	}
	    


		public static Object OLD_doSomethingExpensive_submit() {
			

	         try {

	 			if(locFound==false) {
	 				Log.d("TAGG","loc not found, returning");
	 				return null;
	 			}
	 		
	 	   	   final int  myDummy= 69;   //goofy necessary flag that wikispeedia uses
	 	       String speed;
	 	        
	 	       if(mph_kph) {
	 	    	   speed= Integer.toString(pegMph);               
	 	       } else {
	 	    	   speed= Integer.toString(pegKph);
	 	       }     	 
	        	 
	            String latString = Double.toString(pegLatitude);
	            String lonString = Double.toString(pegLongitude);
	            String alt_metersString = Double.toString(pegAltitude_meters);
	            String dummy=      Integer.toString(myDummy);
	        	String direction=  Float.toString(pegCog);
	        	String hours=      "";
	        	
	        	//instead of clearsigns, insert directly in the table.
			    Signs mySign = new Signs();		      
			    mySign.lat= pegLatitude;
			    mySign.lng= pegLongitude;
			    mySign.cog= Math.round(pegCog);
			    mySign.mph= pegMph;
			    mySign.kph= pegKph;
			    mySign.label= pegName;
				try {  	  
					signs.add(mySign);
				} catch (IllegalArgumentException nsme) {
					/* failure */
					//Log.d("TAGG","ERR: cant add to signs List, clearing it. That may help. Not sure if this is best...");
					clearSigns();		
					theString=  "5";
				}
	
	        	//before http, set off a failsafe timer to end it all so we dont get ANR hangs!!!
	            if(true) {
		             //Log.d("TAGG","in thread: NOW 30 second timer!");
		             mmTimer_submit = new Timer("Submit_FailafeTimer");
	
		             TimerTask mmTimerTask = new TimerTask() {
		                 public void run() {
		                 		mmTimer_submit.cancel();
		                 		//Log.d("TAGG","Fail timeout: finishB");
		                 		//finish();
		                 }
		             };
		             
		             mmTimer_submit.schedule(mmTimerTask, 30000, 30000);             
	            }
	            
	   	        String mmmphval,mmkphval;
	   	        URL url = null;
	   	        StringBuffer response = new StringBuffer("");
	   	     
                if(mph_kph == true) {
                	mmmphval= speed;
                	mmkphval=dummy;
                } else {
                	mmmphval= dummy;
                	mmkphval=speed;
                }
	            try {
		        	url = new URL("http://www.wikispeedia.org/a/process_submit_bb4.php?" +
		        			"mlat=" + latString +			
		        			"&mlon=" + lonString +			
		        			"&malt_meters=" + alt_metersString +			
		        			"&mmph=" + mmmphval +			
		        			"&mkph=" + mmkphval +
		        			"&mtag=" + pegName + "\32" + pegName + 
		        			"&mcog=" + direction +
		        			"&mhours=" + hours +
		        			"&memail=" + pegEmail +
		        			"&mbitcoin=" + pegBitcoin
		        			);
		        	//System.out.println(url.toString());
		        	Log.d("TAGG",url.toString());
		        } catch (MalformedURLException e) {
		        	//Log.e(e.getMessage(), null);
		        }
		        if (url != null) {
		        	try {
		        		HttpURLConnection urlConn = (HttpURLConnection) url
		                	.openConnection();
		                BufferedReader in = new BufferedReader(new InputStreamReader(
		                		urlConn.getInputStream()));
		                String inputLine;
		                while ((inputLine = in.readLine()) != null) {	
		                	//System.out.println(inputLine);
		                	response.append( inputLine );
		                }       
		                in.close();
		                urlConn.disconnect();
		        	} catch (IOException e) {
		        		System.out.println(e.toString());
		        	}
		        }
	            
	            
	            
	            
	            
	            
	            
	            
                
         		mmTimer_submit.cancel();
         		//Log.d("TAGG","Success. finishZ ");
         		//finish();
         
            }catch (Exception e) {
                e.printStackTrace();
                Log.d("TAGG","Err try catch caught in submit");
            }
	         
	         return null;         		
		}
		
	    
		public static Object doSomethingExpensive_submit() throws UnsupportedEncodingException {  
	      {

		       

		 			if(locFound==false) {
		 				Log.d("TAGG","loc not found, returning");
		 				return null;
		 			}
		 		
		 	   	   final int  myDummy= 69;   //goofy necessary flag that wikispeedia uses
		 	       String speed;
		 	        
		 	       if(mph_kph) {
		 	    	   speed= Integer.toString(pegMph);               
		 	       } else {
		 	    	   speed= Integer.toString(pegKph);
		 	       }     	 
		        	 
		            String latString = Double.toString(pegLatitude);
		            String lonString = Double.toString(pegLongitude);
		            String alt_metersString = Double.toString(pegAltitude_meters);
		            String dummy=      Integer.toString(myDummy);
		        	String direction=  Float.toString(pegCog);
		        	String hours=      "";
		        	
		        	//instead of clearsigns, insert directly in the table.
				    Signs mySign = new Signs();		      
				    mySign.lat= pegLatitude;
				    mySign.lng= pegLongitude;
				    mySign.cog= Math.round(pegCog);
				    mySign.mph= pegMph;
				    mySign.kph= pegKph;
				    mySign.label= pegName;
					try {  	  
						signs.add(mySign);
					} catch (IllegalArgumentException nsme) {
						/* failure */
						//Log.d("TAGG","ERR: cant add to signs List, clearing it. That may help. Not sure if this is best...");
						clearSigns();		
						theString=  "5";
					}
		
		        	//before http, set off a failsafe timer to end it all so we dont get ANR hangs!!!
		            if(true) {
			             //Log.d("TAGG","in thread: NOW 30 second timer!");
			             mmTimer_submit = new Timer("Submit_FailafeTimer");
		
			             TimerTask mmTimerTask = new TimerTask() {
			                 public void run() {
			                 		mmTimer_submit.cancel();
			                 		//Log.d("TAGG","Fail timeout: finishB");
			                 		//finish();
			                 }
			             };
			             
			             mmTimer_submit.schedule(mmTimerTask, 30000, 30000);             
		            }
		            
		   	        String mmmphval,mmkphval;
		   	    
		   	        StringBuffer response = new StringBuffer("");
		   	     
	                if(mph_kph == true) {
	                	mmmphval= speed;
	                	mmkphval=dummy;
	                } else {
	                	mmmphval= dummy;
	                	mmkphval=speed;
	                }
	                
	           // Create data variable for sent values to server  
	           
	            String data = URLEncoder.encode("mlat", "UTF-8") 
	                         + "=" + URLEncoder.encode(latString, "UTF-8"); 
	 
	            data += "&" + URLEncoder.encode("mlon", "UTF-8") + "="
	                        + URLEncoder.encode(lonString, "UTF-8"); 
	 
	            data += "&" + URLEncoder.encode("malt_meters", "UTF-8") 
	                        + "=" + URLEncoder.encode(alt_metersString, "UTF-8");
	 
	            data += "&" + URLEncoder.encode("mmph", "UTF-8") 
	                        + "=" + URLEncoder.encode(mmmphval, "UTF-8");

	            data += "&" + URLEncoder.encode("mkph", "UTF-8") 
	                        + "=" + URLEncoder.encode(mmkphval, "UTF-8");

	            data += "&" + URLEncoder.encode("mtag", "UTF-8") 
	                        + "=" + URLEncoder.encode(pegName, "UTF-8");

	            data += "&" + URLEncoder.encode("mcog", "UTF-8") 
	                        + "=" + URLEncoder.encode(direction, "UTF-8");

	            data += "&" + URLEncoder.encode("mhours", "UTF-8") 
	                        + "=" + URLEncoder.encode(hours, "UTF-8");

	            data += "&" + URLEncoder.encode("memail", "UTF-8") 
	                        + "=" + URLEncoder.encode(pegEmail, "UTF-8");

	            data += "&" + URLEncoder.encode("mbitcoin", "UTF-8") 
	                        + "=" + URLEncoder.encode(pegBitcoin, "UTF-8");
	            
	            String text = "";
	            BufferedReader reader=null;
	 
	            // Send data 
	          try
	          { 
	            
	              // Defined URL  where to send data
	              URL url = new URL("http://www.wikispeedia.org/a/process_submit_bb5.php");
	               
	             
	            	  
	           // Send POST data request
	 
	            URLConnection conn = url.openConnection(); 
	            conn.setDoOutput(true); 
	            OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); 
	            wr.write( data ); 
	            wr.flush(); 
	        
	            // Get the server response 
	             
	          reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
	          StringBuilder sb = new StringBuilder();
	          String line = null;
	          
	          // Read Server Response
	          while((line = reader.readLine()) != null)
	              {
	                     // Append server response in string
	                     sb.append(line + "\n");
	              }
	              
	              
	              text = sb.toString();
	          }
	          catch(Exception ex)
	          {
	               
	          }
	          finally
	          {
	              try
	              {
	   
	                  reader.close();
	              }
	 
	              catch(Exception ex) {}
	          }
	                
	          
	      }
		return null;
	   
	  }

		

	    public static void startLongRunningOperation_submit() {

	        // Fire off a thread to do some work that we shouldn't do directly in the UI thread
	        Thread t = new Thread("startLongRunningOperation_submit") {
	            public void run() {
	            	try {
						Object mResults = doSomethingExpensive_submitAndOrDelete();
					} catch (UnsupportedEncodingException e) {
						e.printStackTrace();
					}
	                mHandler_submit.post(mUpdateResults_submit);
	            }
	        };
	        t.start();
	    }


	    
	    public static double haversign(double lat1, double lat2, double lon1, double lon2 ) {
	    	   //Haversign formula courtesy: 
	    	   //http://www.movable-type.co.uk/scripts/latlong.html
	 	   
	 	   double R = 6371; // km
	 	   double dLat = Math.toRadians(lat2-lat1); 
	 	   double dLon = Math.toRadians(lon2-lon1); 
	 	   double a1 = Math.sin(dLat/2) * Math.sin(dLat/2) +
	 	           Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * 
	 	           Math.sin(dLon/2) * Math.sin(dLon/2);
	 	   double c = 2 * Math.atan2(Math.sqrt(a1), Math.sqrt(1-a1));
	 	   double d = R * c;
	 	   if(mph_kph){
	 		   d= d * 0.621371192;    //miles= km * 0.62miles/km
	 	   } else {
	 		   //already in km		   
	 	   }
	 	   return d;
	    }

	    
	    
	    	
	    


	    

}
